
#include "hal.h"

#define XIP_FLASH_DELAY     1000 


void xip_sram_Delay(volatile uint32_t fu32_Delay)
{
    while (fu32_Delay--);
}


void __SPI_Write_Data(uint8_t *pData, uint32_t Size)
{
    /* Clear Batch Done Flag  */
    SPI7->STATUS |= SPI_STATUS_TX_BATCH_DONE;
    SPI7->STATUS |= SPI_STATUS_BATCH_DONE;
    /* Clear TX FIFO */
    SPI7->TX_CTL |= SPI_TX_CTL_FIFO_RESET;
    SPI7->TX_CTL &= ~SPI_TX_CTL_FIFO_RESET;   
    /* Set Data Size */
    SPI7->BATCH = Size;   
    /* Tx Enable */
    SPI7->TX_CTL |= SPI_TX_CTL_EN;
    /* Transmit Start */
    SPI7->CS |= SPI_CS_CS0;
    while(Size > 0)
    {
        /* Wait Tx FIFO Not Full */
        while (SPI7->STATUS & SPI_STATUS_TX_FIFO_FULL);       
        SPI7->DAT = *pData++;
        Size--;
    }
    /* Wait Transmit Done */
    while (!(SPI7->STATUS & SPI_STATUS_TX_BATCH_DONE));  
End:
    /* Clear Batch Done Flag  */
    SPI7->STATUS |= SPI_STATUS_TX_BATCH_DONE;
    SPI7->STATUS |= SPI_STATUS_BATCH_DONE;
    /* Tx Disable */
    SPI7->TX_CTL &= (~SPI_TX_CTL_EN); 
    /* Transmit End */
    SPI7->CS &= (~SPI_CS_CS0);
}


void __SPI_Read_Data(uint8_t *pData, uint32_t Size)
{
    /* Clear Batch Done Flag  */
    SPI7->STATUS |= SPI_STATUS_RX_BATCH_DONE;
    SPI7->STATUS |= SPI_STATUS_BATCH_DONE;
    /* Set Data Size */
    SPI7->BATCH = Size;
    /* Rx Enable */
    SPI7->RX_CTL |= SPI_RX_CTL_EN;
    /* Receive Start */
    SPI7->CS |= SPI_CS_CS0;  
    while(Size > 0)
    {
        /* Wait Rx FIFO Not Empty */
        while (SPI7->STATUS & SPI_STATUS_RX_FIFO_EMPTY);
        *pData++ = SPI7->DAT;
        Size--;
    }
    /* Wait Transmit Done */
    while (!(SPI7->STATUS & SPI_STATUS_RX_BATCH_DONE));
End:   
    /* Clear Batch Done Flag  */
    SPI7->STATUS |= SPI_STATUS_RX_BATCH_DONE;
    SPI7->STATUS |= SPI_STATUS_BATCH_DONE;
    /* Rx Disable */
    SPI7->RX_CTL &= (~SPI_RX_CTL_EN);
    /* Receive End */
    SPI7->CS &= (~SPI_CS_CS0);
}

void SPI_GPIOInit(void)
{
    /* Enable SPI7 */
    RCC->AHB3ENR |= BIT0; 
    /* Enable GPIOB */    
    RCC->AHB2ENR |= BIT1;    
    /* Alternate Function */
    GPIOB->AF0 &= ~(0xFF000000U);
    GPIOB->AF0 |= (GPIO_FUNCTION_0 << 24) | (GPIO_FUNCTION_0 << 28);
    GPIOB->AF1 &= ~(0xF0FFU);
    GPIOB->AF1 |= (GPIO_FUNCTION_0 << 0) | (GPIO_FUNCTION_0 << 4) | (GPIO_FUNCTION_0 << 12);
    /* Configure the IO drive capability */
    GPIOB->DS0 &= ~(0xFF000000U);
    GPIOB->DS0 |= (GPIO_DRIVE_LEVEL3 << 24) | (GPIO_DRIVE_LEVEL3 << 28);
    GPIOB->DS1 &= ~(0xFFFFU);
    GPIOB->DS1 |= (GPIO_DRIVE_LEVEL3 << 0) | (GPIO_DRIVE_LEVEL3 << 4) | (GPIO_DRIVE_LEVEL3 << 8) | (GPIO_DRIVE_LEVEL3 << 12);
    /* Configure the IO Output Type */
    GPIOB->OTYP &= ~(0xFC0U) ;
    /* Activate the Pull-up or Pull down resistor for the current IO */
    GPIOB->PUPD &= ~(0xFFF000U);
    GPIOB->PUPD |= (GPIO_PULLDOWN << 12) | (GPIO_PULLDOWN << 14) | (GPIO_PULLDOWN << 22);
    GPIOB->PUPD |= (GPIO_PULLUP << 16) | (GPIO_PULLUP << 18) | (GPIO_PULLUP << 20);
    /* Configure schmitt input */
    GPIOB->SMIT |= 0xFC0U;
    /* Configure IO Direction mode (Input, Output, Alternate or Analog) */
    GPIOB->MD &= ~(0xFFF000U);
    GPIOB->MD |= (GPIO_MODE_AF_PP << 12) | (GPIO_MODE_AF_PP << 14) | (GPIO_MODE_AF_PP << 16) | \
                 (GPIO_MODE_AF_PP << 18) | (GPIO_MODE_OUTPUT_PP << 20) | (GPIO_MODE_AF_PP << 22);
       
}

void SPI_Init(void)
{
    /* Automatic change direction */
    SPI7->CTL |= (SPI_CTL_IO_MODE);
    /* Set SPI Work mode */
    SPI7->CTL |= SPI_CTL_MST_MODE;
    /* Set SPI First Bit */
    SPI7->CTL &= ~SPI_CTL_LSB_FIRST;
    /* Set SPI Work Mode */
    SPI7->CTL = ((SPI7->CTL) & (~(SPI_CTL_CPHA | SPI_CTL_CPOL))) | (SPI_WORK_MODE_0);
    /* Set SPI X_Mode */
    SPI7->CTL = ((SPI7->CTL) & (~SPI_CTL_X_MODE)) | (SPI_4X_MODE);
    /* Set SPI BaudRate Prescaler */
    SPI7->BAUD = ((SPI7->BAUD) & (~0x0000FFFF)) | (SPI_BAUDRATE_PRESCALER_4);
    /* Disable All Interrupt */
    SPI7->IE = 0x00000000;
}

/************************************************************************
 * Description: XIP_Flash_Init.
 ************************************************************************/ 
void XIP_Flash_Init(void)
{  
    /* Reset SPI7 */
    RCC->AHB3RSTR &= ~(1<<0);
    xip_sram_Delay(5);
    RCC->AHB3RSTR |= (1<<0);
		
    SPI_GPIOInit();
    
    /* First Set CS HIGH */
    GPIOB->BSC = GPIO_PIN_10; 
    
    xip_sram_Delay(5);  
    
    SPI_Init();
    
    SPI7->CTL = ((SPI7->CTL) & (~SPI_CTL_X_MODE)) | SPI_1X_MODE; 
} 

void SPI_Nor_Flash_PowerDown(void)
{ 
    uint8_t lu8_DataBuffer[1];
    
    SPI7->CTL = ((SPI7->CTL) & (~SPI_CTL_X_MODE)) | SPI_1X_MODE; 
    
    lu8_DataBuffer[0] = 0xB9;

    /* CS Select */
    GPIOB->BSC = GPIO_PIN_10 << 16U;
    /* Send command */
    __SPI_Write_Data(lu8_DataBuffer, 1);
    /* CS Realse */
    GPIOB->BSC = GPIO_PIN_10; 
}

void SPI_Nor_Flash_Wakeup(void)
{  
    uint8_t lu8_DataBuffer[1]; 
    
    SPI7->CTL = ((SPI7->CTL) & (~SPI_CTL_X_MODE)) | SPI_1X_MODE;   
    
    lu8_DataBuffer[0] = 0xAB;

    /* CS Select */
    GPIOB->BSC = GPIO_PIN_10 << 16U;
    /* Send command */
    __SPI_Write_Data(lu8_DataBuffer, 1);
    /* CS Realse */
    GPIOB->BSC = GPIO_PIN_10; 
}

uint16_t SPI_Nor_Flash_Read_ID(void)
{
    uint8_t lu8_DataBuffer[4];
    
    lu8_DataBuffer[0] = 0x90;
    lu8_DataBuffer[1] = 0;
    lu8_DataBuffer[2] = 0;
    lu8_DataBuffer[3] = 0;

    /* CS Select */
    GPIOB->BSC = GPIO_PIN_10 << 16U;
    /* Send command */
    __SPI_Write_Data(lu8_DataBuffer, 4);
    /* Recieve Manufacture ID and Device ID */
    __SPI_Read_Data(lu8_DataBuffer, 2);
    /* CS Realse */
    GPIOB->BSC = GPIO_PIN_10; 
    
    return ((uint16_t)lu8_DataBuffer[0] << 8 | (uint16_t)lu8_DataBuffer[1]);
}

void UART_SendBytes(uint8_t *pdata, uint32_t len)
{
    while(len--)
    {
        UART1->DR = *pdata++;        
        while (!(UART1->FR & UART_FR_TXFE));
    }
}


uint8_t SPI_Nor_Switch_to_FIFO_MODE(void)
{
    xip_sram_Delay(XIP_FLASH_DELAY);    // Delay * 8, max value = 255 * 8 = 2040     
    RCC->AHB2ENR |= BIT1;  
    xip_sram_Delay(1); 
    SPI7->MEMO_ACC.acc_en = 0; 
    GPIOB->MD = ( (GPIOB->MD) & (~(0x03U << 20) ) ) | (0x1U << 20);    // PB10 to GPIO Mode   
    GPIOB->BSC = GPIO_PIN_10;   
    return 0;   
}

void SPI_Nor_Switch_to_XIP_MODE(void)
{
    RCC->AHB2ENR |= BIT1;     
    xip_sram_Delay(1);   
    GPIOB->MD = ((GPIOB->MD) & (~(0x03U << 20) ) ) | (0x2U << 20);    // PB10 to AF Mode       
    xip_sram_Delay(2);  
    SPI7->MEMO_ACC.acc_en = 1;       
    xip_sram_Delay(XIP_FLASH_DELAY);    
}


void Enter_Powerdown_RunInSRAM(void)
{
    uint16_t lu16_ID;
    uint8_t MID_Buf[] = "MID: EB14\n";
    
    __set_PRIMASK(1);    // disable interrupt
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;     // disable systick 
    SCB->ICSR = BIT25;   // clear systick pending bit  
    
    SPI_Nor_Switch_to_FIFO_MODE();
    
    lu16_ID = SPI_Nor_Flash_Read_ID();
    
    if(lu16_ID == 0xEB14)
    {
        UART_SendBytes(MID_Buf, strlen((char *)MID_Buf));
    }

    xip_sram_Delay(500);

    SPI_Nor_Flash_PowerDown();
    
    PMU->CTRL0 = (PMU->CTRL0 & (~(PMU_CTRL0_LPMS_Msk))|(PMU_CTL0_LPMS_POWERDOWN & PMU_CTRL0_LPMS_Msk));//Powerdown Mode

    SCB->SCR |= ((uint32_t)SCB_SCR_SLEEPDEEP_Msk);   // Set SLEEPDEEP bit of Cortex System Control Register 

    /* Wait For Interrupt */   
    __WFI();

    /* clear SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); 
    
    __set_PRIMASK(0);    // enable interrupt  
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;  // enable systick

    SPI_Nor_Flash_Wakeup();
    
    xip_sram_Delay(500);
    
    SPI_Nor_Switch_to_XIP_MODE();    
    
}


void Enter_Stop_RunInSRAM(void)
{
    uint16_t lu16_ID;
    uint8_t MID_Buf[] = "MID: EB14\n";
    
    __set_PRIMASK(1);    // disable interrupt
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;     // disable systick 
    SCB->ICSR = BIT25;   // clear systick pending bit  

    /* Clock switch to RCH */
    RCC->RC64MCR &= ~RCC_RC64MCR_RC64MDIV;
    RCC->RC64MCR |= RCC_RC64MCR_RC64MEN;
    while (!(RCC->RC64MCR & RCC_RC64MCR_RC64MRDY));
    RCC->CCR1 &= ~RCC_CCR1_SYSCLKSEL;	/* sysclk = RC64M  */
            
    /* XTH Disable */
    RCC->XTHCR &= (~RCC_XTHCR_XTHEN);
    /* PLL sleep */    
    RCC->PLLCR |= RCC_PLLCR_PLLSLEEP;
    /* RC32K Disable */ 
    RCC->RC32KCR &= (~RCC_RC32KCR_RC32KEN); 
    /* Buzzer1 Disable */
    RCC->CLKOCR &= (~RCC_CLKOCR_BUZZER1EN); 
    
    RCC->AHB1ENR = 0;
    RCC->AHB2ENR = RCC_AHB2ENR_GPIOBCKEN;
    RCC->AHB3ENR = 0;
    RCC->APB1ENR = RCC_APB1ENR_PMUCKEN;
    RCC->APB2ENR = RCC_APB2ENR_EXTICKEN;

    /* LVD Disable */
    PMU->CTRL1 &= (~PMU_CTRL1_LVDEN);
    
    /* RC64M automatic shutdownM */
    PMU->CTRL0 |= PMU_CTRL0_RC64MPDEN;

    /* The MLDO12 voltage is automatically adjusted to 0.8V */
    PMU->CTRL0 &= (~PMU_CTRL0_MLDO12_LV_Msk);
    PMU->CTRL0 |= (0x03 << PMU_CTRL0_MLDO12_LV_Pos);
    
    /* Low power consumption mode selection STOP mode */
    PMU->CTRL0 = (PMU->CTRL0 & (~(PMU_CTRL0_LPMS_Msk))) | (PMU_CTL0_LPMS_STOP & PMU_CTRL0_LPMS_Msk);
    
    /* Set SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR |= ((uint32_t)SCB_SCR_SLEEPDEEP_Msk);   
    
    /* Wait For Interrupt */   
    __WFI();
    
    /* clear SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); 
    
    RCC->AHB3ENR = RCC_AHB3ENR_SPI7CKEN;
    xip_sram_Delay(500000);
    PMU->CTRL0 &= (~PMU_CTRL0_MLDO12_LV_Msk);
    __set_PRIMASK(0);    // enable interrupt  
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;  // enable systick

}


